package com.ldk.api;

import java.io.BufferedReader;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.commons.lang.StringUtils;
import org.springframework.http.MediaType;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.multipart.MultipartFile;

import com.alibaba.fastjson.JSON;
import com.ldk.base.framework.util.SignUtil;

@Controller
@RequestMapping("/request")
public class RequestController extends BaseController {
	
	/**
	 * POST请求方法
	 * @param request
	 * @param response
	 * @return 响应对象ResponseObject
	 */
	@ResponseBody
	@RequestMapping(value="/post",method = RequestMethod.POST, produces=MediaType.APPLICATION_JSON_VALUE)
	public Object post(HttpServletRequest request, HttpServletResponse response)
	{	
		ResponseObject responseObject = ResponseResult.create("", "");
		response.setCharacterEncoding("UTF-8");
		String json = "";
		try{
			BufferedReader reader = request.getReader();

			String buffer = null;
			StringBuffer stringBuffer = new StringBuffer();

			while((buffer = reader.readLine()) != null){
				stringBuffer.append(buffer);
			}
			json  = stringBuffer.toString();
		}
		catch(Exception e){
			logger.error(e.getMessage());
		}
		if(StringUtils.isBlank(json)){
			return ResponseResult.exception(responseObject, ErrorCode.SERIALIZE_ERROR);
		}

		RequestObject reqObject = null;
		try{
			reqObject = JSON.parseObject(json, RequestObject.class);
		}
		catch(Exception e){
			logger.error(e.getMessage());
		}
		if(!validRequest(reqObject)){
			return ResponseResult.exception(responseObject, ErrorCode.SERIALIZE_ERROR);
		}
		if (Consts.CHECK_SIGN) {
			String sign = request.getHeader("sign");
			int version = reqObject.getVersion();

			if(!checkSignature(sign, version, json)){
				return ResponseResult.exception(responseObject, ErrorCode.SIGN_ERROR);
			}
		}
		return execute(reqObject);
	}

	/**
	 * GET请求
	 * @param json
	 * @param request
	 * @param response
	 * @return 响应对象ResponseObject
	 */
	@ResponseBody
	@RequestMapping(value="/get", method = RequestMethod.GET,produces=MediaType.APPLICATION_JSON_VALUE)
	public Object get(@RequestParam(value="json",required=true) String json,
			HttpServletRequest request, HttpServletResponse response)
	{
		ResponseObject responseObject = ResponseResult.create("", "");
		response.setCharacterEncoding("UTF-8");
		if(StringUtils.isBlank(json)){
			return ResponseResult.exception(responseObject, ErrorCode.SERIALIZE_ERROR);
		}

		RequestObject reqObject = null;
		try{
			reqObject = JSON.parseObject(json, RequestObject.class);
		}
		catch(Exception e){
			logger.error(e.getMessage());
		}
		if(!validRequest(reqObject)){
			return ResponseResult.exception(responseObject, ErrorCode.SERIALIZE_ERROR);
		}

		if (Consts.CHECK_SIGN) {
			String sign = request.getHeader("sign");
			int version = reqObject.getVersion();

			if(!checkSignature(sign, version, json)){
				return ResponseResult.exception(responseObject, ErrorCode.SIGN_ERROR);
			}
		}
		return execute(reqObject);
	}

	/**
	 * 混合模式请求
	 * @param json 请求参数
	 * @param files 上传文件
	 * @param request
	 * @param response
	 * @return 响应对象ResponseObject
	 */
	@ResponseBody
	@RequestMapping(value="/mixed",method={RequestMethod.POST} ,produces = MediaType.APPLICATION_JSON_VALUE)
	public Object mixRequest(@RequestParam(value="json",required=true) String json,
			                 @RequestParam(value="files",required=false,defaultValue="") MultipartFile[] files,
			                 HttpServletRequest request, HttpServletResponse response)
	{
		ResponseObject responseObject = ResponseResult.create("", "");
		response.setCharacterEncoding("UTF-8");
		if(StringUtils.isBlank(json)){
			return ResponseResult.exception(responseObject, ErrorCode.SERIALIZE_ERROR);
		}
		
		RequestObject reqObject = null;
		try{
			reqObject = JSON.parseObject(json, RequestObject.class);
		}
		catch(Exception e){
			logger.error(e.getMessage());
		}
		if(!validRequest(reqObject)){
			return ResponseResult.exception(responseObject, ErrorCode.SERIALIZE_ERROR);
		}
		if (Consts.CHECK_SIGN) {
			String sign = request.getHeader("sign");
			int version = reqObject.getVersion();

			if (!checkSignature(sign, version, json)) {
				return ResponseResult.exception(responseObject,ErrorCode.SIGN_ERROR);
			}
		}
		if(files != null && files.length > 0){
			List<FileItem> fileList = new ArrayList<FileItem>();
			for(MultipartFile file : files){
				FileItem fileItem = saveFile("upload", file);
				if(fileItem == null ||
				   StringUtils.isEmpty(fileItem.getFileUrl()))
					continue;
				fileList.add(fileItem);
			}
			if(reqObject.getParms() == null){
				reqObject.setParms(new HashMap<String, Object>());
			}
			reqObject.getParms().put("fileList", fileList);
		}
		//日志
		logger.error(JSON.toJSONString(reqObject));

		return execute(reqObject);
	}
	
	/**
	 * 文件上传模式请求
	 * @param module 文件模块
	 * @param files 上传文件
	 * @param request
	 * @param response
	 * @return 响应对象ResponseObject
	 */
	@ResponseBody
	@RequestMapping(value="/upload",method={RequestMethod.POST} ,produces = MediaType.APPLICATION_JSON_VALUE)
	public Object uploadRequest(@RequestParam(value="module",required=true,defaultValue="upload") String module,
			   					@RequestParam(value="files",required=false,defaultValue="") MultipartFile[] files,
			                    HttpServletRequest request, HttpServletResponse response)
	{
		response.setCharacterEncoding("UTF-8");
		if(StringUtils.isBlank(module)){
			module = "upload";
		}
		List<FileItem> fileList = new ArrayList<FileItem>();
		if(files != null && files.length > 0){
			for(MultipartFile file : files){
				FileItem fileItem = saveFile("upload", file);
				if(fileItem == null ||
				   StringUtils.isEmpty(fileItem.getFileUrl()))
					continue;
				fileList.add(fileItem);
			}
		}
		
		return fileList;
	}

	/**
	 * 验证请求对象是否有效
	 * @param reqObject
	 * @return false 无效 true 有效
	 */
	private Boolean validRequest(RequestObject reqObject){
		if(reqObject == null ||
				reqObject.getVersion() == null ||
				StringUtils.isEmpty(reqObject.getModule()) ||
				StringUtils.isEmpty(reqObject.getMethod())){
			return false;
		}
		return true;
	}

	/**
	 * 验证是否有效请求
	 * @param sign 签名
	 * @param version 客户端版本
	 * @param json 参数json字符串
	 * @return true有效false非法
	 */
	private Boolean checkSignature(String sign, int version, String json){
		// add by zhangl 2015-07-09
		if (null==sign) {
			return false;
		}
		String rawSign = SignUtil.encrypt(json, version, Consts.System_Sign_EncryptKey);
		return sign.equalsIgnoreCase(rawSign);
	}

	/**
	 * 执行请求
	 * @param requestObject
	 * @return 响应对象ResponseObject
	 */
	private Object execute(RequestObject requestObject)
	{
		if(requestObject == null || 
		   StringUtils.isEmpty(requestObject.getModule()) || 
	       StringUtils.isEmpty(requestObject.getMethod()))
		{  
			return ResponseResult.exception(requestObject, ErrorCode.SERIALIZE_ERROR);
		}
		try{
			Object instance =  SpringContextUtil.getBean(requestObject.getModule());
			if(instance == null){
				return ResponseResult.exception(requestObject, ErrorCode.MODULE_EMPTY);
			}

			Class clazz = instance.getClass();

			if(clazz == null){
				return ResponseResult.exception(requestObject, ErrorCode.MODULE_ERROR);
			}
			//获取请求处理的方法，所有请求处理方法的参数都是Map<String,Object>
			Method curMethod = null;
			try{
				if(requestObject.getParms() == null || 
				   requestObject.getParms().isEmpty()){
					curMethod = clazz.getMethod(requestObject.getMethod());
				}
				else{
					curMethod = clazz.getMethod(requestObject.getMethod(), Map.class);
				}
			}
			catch(SecurityException e){
				logger.error(e.getMessage());
				return ResponseResult.exception(requestObject, ErrorCode.HAVE_NOT_METHOD);
			}
			catch(NoSuchMethodException e){
				logger.error(e.getMessage());
				return ResponseResult.exception(requestObject, ErrorCode.HAVE_NOT_METHOD);
			}
			catch(Exception e){
				logger.error(e.getMessage());
				return ResponseResult.exception(requestObject, ErrorCode.HAVE_NOT_METHOD);
			}
			if(curMethod == null){
				return ResponseResult.exception(requestObject, ErrorCode.METHOD_EMPTY);
			}
			//如果请求接口的参数设置调用接口的版本时要执行过滤
			if(requestObject.getVersion() > 1){
				if(!curMethod.isAnnotationPresent(ApiVersion.class)){
					return ResponseResult.exception(requestObject, ErrorCode.METHOD_VERSION_ERROR);
				}
				ApiVersion apiVersion = curMethod.getAnnotation(ApiVersion.class);
				if(apiVersion == null){
					return ResponseResult.exception(requestObject, ErrorCode.METHOD_VERSION_ERROR);
				}
				//判断请求接口是否允许访问
				Boolean allowVersion = false;
				int[] versions = apiVersion.value();
				for (int version : versions) {
					if(version == requestObject.getVersion()){
						allowVersion = true;
					}
				}
				if(!allowVersion){
					return ResponseResult.exception(requestObject, ErrorCode.METHOD_VERSION_ERROR);
				}
			}
			if(Consts.CHECK_TOKEN){
				//判断方法是否要进行Token验证
				if(curMethod.isAnnotationPresent(CheckToken.class)){
					CheckToken checkToken = curMethod.getAnnotation(CheckToken.class);
					//验证
					if(checkToken != null && 
					   checkToken.check() &&
					   requestObject.getParms() != null && 
					   !requestObject.getParms().isEmpty() &&
					   !StringUtils.isBlank(requestObject.getPlatform())){

						RequestPlatform platform = RequestPlatform.getPlatform(requestObject.getPlatform());
						//如果请求的方法要求验证token是那个平台的请求才执行token验证
						if(requestObject.getPlatform().equalsIgnoreCase(checkToken.platform().getName())){
							String tokenKey = checkToken.tokenKey();
							String token = requestObject.getToken();
							String tokenKeyValue = String.valueOf(requestObject.getParms().get(tokenKey));
							//token错误
							if(!checkToken(tokenKey, tokenKeyValue, token, platform)){
								return ResponseResult.exception(requestObject, ErrorCode.TOKEN_ERROR);
							}
						}
					}
				}
			}
			
			try{
				Object result = null;
				//请求参数
				//如果方法没有参数
				if(requestObject.getParms() == null || 
				   requestObject.getParms().isEmpty()){
					result = curMethod.invoke(instance);
				}
				else{//有参数类型
					Map<String, Object> parms = requestObject.getParms();
					if(parms != null && !parms.isEmpty()){
						//将token参数放进去
						String token = StringUtils.isEmpty(requestObject.getToken()) ? "" : requestObject.getToken();
						parms.put("token", token);
						parms.put("version", requestObject.getVersion());
					}
					result = curMethod.invoke(instance, parms);
				}
				return result;
			}
			catch(Exception e){
				logger.error(e.getMessage());
			}
			return ResponseResult.exception(requestObject, ErrorCode.INVOKE_METHOD_EXCEPTION);
		}
		catch(Exception e){
			logger.error(e.getMessage());
		}
		return ResponseResult.exception(requestObject, ErrorCode.UNKNOWN);
	}

}
